package com.jl.smartcard.ui.editors.cardfile;

import java.util.ArrayList;
import java.util.List;

import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.jface.layout.TableColumnLayout;
import org.eclipse.jface.viewers.CellEditor;
import org.eclipse.jface.viewers.ColumnPixelData;
import org.eclipse.jface.viewers.ICellModifier;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.TableViewerColumn;
import org.eclipse.jface.viewers.TextCellEditor;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.SashForm;
import org.eclipse.swt.custom.StyledText;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Item;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.MessageBox;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.TableItem;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorSite;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.part.EditorPart;
import org.eclipse.wb.swt.SWTResourceManager;

import com.jl.card.SWException;
import com.jl.card.file.CardFile;
import com.jl.card.file.IFileInfo;
import com.jl.smartcard.core.actions.VerifyAction;
import com.jl.util.HexUtil;

public class CardFileEditor extends EditorPart {
	public static final String ID = "com.jl.core.editors.cardfile.CardFileEditor"; //$NON-NLS-1$
	private StyledText stFileInfo;

	private CardFile file;
	private Composite composite;
	private Table table;
	private TableViewer tableViewer;

	public final static int TABLE_INDEX = 1;
	public final static int TABLE_VALUE = 2;

	private CellEditor[] editors = new CellEditor[2];

	public final static String[] COLUME_NAME = new String[] { "INDEX", "VALUE" };
	protected static final int TEXT_MARGIN = 3;
	private TableColumn tblclmnIndex;
	private TableViewerColumn tableViewerColumn;
	private TableColumn tblclmnValue;
	private TableViewerColumn tableViewerColumn_1;

	public CardFileEditor() {

	}

	/**
	 * Create contents of the editor part.
	 * 
	 * @param parent
	 */
	@Override
	public void createPartControl(Composite parent) {
		parent.setLayout(new GridLayout(1, false));

		SashForm sashForm = new SashForm(parent, SWT.VERTICAL);
		sashForm.setBackground(SWTResourceManager.getColor(SWT.COLOR_WHITE));
		sashForm.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1,
				1));

		stFileInfo = new StyledText(sashForm, SWT.BORDER | SWT.READ_ONLY
				| SWT.V_SCROLL);
		stFileInfo.setFont(SWTResourceManager.getFont("Courier New", 11,
				SWT.NORMAL));

		composite = new Composite(sashForm, SWT.NONE);
		TableColumnLayout tcl_composite = new TableColumnLayout();
		composite.setLayout(tcl_composite);

		tableViewer = new TableViewer(composite, SWT.BORDER
				| SWT.FULL_SELECTION);
		table = tableViewer.getTable();
		table.setFont(SWTResourceManager.getFont("Courier New", 11, SWT.NORMAL));
		table.setHeaderVisible(true);
		table.setLinesVisible(true);

		table.addListener(SWT.MeasureItem, new Listener() {
			@Override
			public void handleEvent(Event event) {
				TableItem item = (TableItem) event.item;
				String text = item.getText(event.index);
				Point size = event.gc.textExtent(text);
				event.width = size.x + 2 * TEXT_MARGIN;
				event.height = Math.max(event.height, size.y + TEXT_MARGIN);
			}
		});
		table.addListener(SWT.PaintItem, new Listener() {
			@Override
			public void handleEvent(Event event) {
				TableItem item = (TableItem) event.item;
				String text = item.getText(event.index);
				/* center column 1 vertically */
				int yOffset = 0;
				if (event.index == 1) {
					Point size = event.gc.textExtent(text);
					yOffset = Math.max(0, (event.height - size.y) / 2);
				}
				event.gc.drawText(text, event.x + TEXT_MARGIN, event.y
						+ yOffset, true);
			}
		});

		table.addListener(SWT.EraseItem, new Listener() {
			@Override
			public void handleEvent(Event event) {
				event.detail &= ~SWT.FOREGROUND;
			}
		});

		tableViewerColumn = new TableViewerColumn(tableViewer, SWT.NONE);
		tblclmnIndex = tableViewerColumn.getColumn();
		tcl_composite.setColumnData(tblclmnIndex, new ColumnPixelData(80, true,
				true));
		tblclmnIndex.setText("INDEX");

		tableViewerColumn_1 = new TableViewerColumn(tableViewer, SWT.NONE);
		tblclmnValue = tableViewerColumn_1.getColumn();
		tcl_composite.setColumnData(tblclmnValue, new ColumnPixelData(440,
				true, true));
		tblclmnValue.setText("VALUE");
		tableViewer.setLabelProvider(new TableLabelProvider());
		tableViewer.setContentProvider(new ContentProvider());
		sashForm.setWeights(new int[] { 191, 230 });

		tableViewer.setColumnProperties(COLUME_NAME);
		editors[0] = null;
		editors[1] = new TextCellEditor(table, SWT.MULTI);
		tableViewer.setCellEditors(editors);
		tableViewer.setCellModifier(new ICellModifier() {

			@Override
			public void modify(Object element, String property, Object value) {
				if (element instanceof Item) {
					element = ((Item) element).getData();
				}
				CardFileObject eo = (CardFileObject) element;
				if (property.equals(COLUME_NAME[1])) {
					String ori = HexUtil.compact(eo.getValue());
					String newVal = HexUtil.compact(value.toString());
					if (ori.equals(newVal)) {
						return;
					}
					eo.setValue((String) value);
					motifyFileToCardFile(eo);
				}
				tableViewer.refresh();
			}

			@Override
			public Object getValue(Object element, String property) {
				if (property.equals(COLUME_NAME[1])) {
					return ((CardFileObject) element).getValue();
				}
				return null;
			}

			@Override
			public boolean canModify(Object element, String property) {
				if (property.equals(COLUME_NAME[0])) {
					return false;
				}
				return true;
			}
		});

	}

	protected void motifyFileToCardFile(CardFileObject eo) {
		try {
			file.select();
		} catch (SWException e) {
			MessageBox box = new MessageBox(getSite().getShell());
			box.setMessage(e.getMessage());
			box.open();
		}
		IFileInfo info = file.getCardFileInfo();
		try {
			if (info.isTransparent()) {
				file.ub(0, eo.getValue());
			} else {
				file.ur(eo.getIndex(), eo.getValue());
			}
		} catch (SWException e) {
			if (e.getSW() == 0x9804) {
				VerifyAction action = new VerifyAction();
				action.init(getSite().getWorkbenchWindow());
				action.run(null);
				if (action.isCancel()) {
					eo.restore();
					return;
				} else {
					motifyFileToCardFile(eo);
				}
			} else {
				MessageBox box = new MessageBox(getSite().getShell());
				box.setMessage(e.getMessage());
				box.open();
			}
			return;
		}

	}

	@Override
	public void setFocus() {
	}

	@Override
	public void doSave(IProgressMonitor monitor) {
	}

	@Override
	public void doSaveAs() {
	}

	@Override
	public void init(IEditorSite site, IEditorInput input)
			throws PartInitException {
		this.setSite(site);
		this.setInput(input);
		this.setPartName(input.getName());
	}

	@Override
	public boolean isDirty() {
		return false;
	}

	@Override
	public boolean isSaveAsAllowed() {
		return false;
	}

	public void setCardFile(CardFile file) {
		this.file = file;
		this.stFileInfo.setText(file.info());
		List<CardFileObject> all = new ArrayList<CardFileObject>();
		try {
			file.select();
			if (file.getCardFileInfo().isTransparent()) {
				byte[] res = file.rb(0, file.size());
				all.add(new CardFileObject(1, res));
			} else {
				for (int i = 1; i <= file.recordNum(); i++) {
					all.add(new CardFileObject(i, file.rr(i)));
				}
			}
		} catch (SWException e) {
			if (e.getSW() == 0x9804) {
				VerifyAction action = new VerifyAction();
				action.init(getSite().getWorkbenchWindow());
				action.run(null);
				if (action.isCancel()) {
					return;
				} else {
					setCardFile(file);
				}
			}
			return;
		}
		tableViewer.setInput(all);
		tableViewer.refresh();
	}
}
